package pers.vankid.sessionkeeper.service;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import pers.vankid.common.model.authc.AuthcUser;
import pers.vankid.common.model.authc.AuthcUserResponse;
import pers.vankid.sessionkeeper.model.SessionKeeper;

import javax.annotation.Resource;
import java.util.Map;
import java.util.Random;

@Service
public class SessionKeeperServiceImpl implements SessionKeeperService {
    @Resource(name = "sessionMap")
    private Map<String, SessionKeeper> sessionMap;
    @Resource(name = "signMap")
    private Map<String, String> signMap;
    @Resource(name = "keyMap")
    private Map<String, String> keyMap;

    @Value("${session-keeper.timeout}")
    private Long timeout;

    /**
     * 登陆
     *
     * @param authcUser
     * @return
     * @throws Exception
     */
    @Override
    public String login(AuthcUser authcUser) throws Exception {
        String key = authcUser.getAuthcKey();
        if (signMap.containsKey(key)) {
            String sign = signMap.get(key);
            boolean isLogon = checkLogin(sign);
            if (isLogon)
                return sign;
            else return createLogin(authcUser);
        } else return createLogin(authcUser);
    }

    /**
     * 初始登录
     *
     * @param authcUser
     * @return
     */
    private String createLogin(AuthcUser authcUser) {
        String key = authcUser.getAuthcKey();
        String sign = createSign();
        signMap.put(key, sign);
        keyMap.put(sign, key);
        SessionKeeper sessionKeeper = new SessionKeeper();
        sessionKeeper.setTimestamp(System.currentTimeMillis());
        sessionKeeper.setAuthcUserResponse(authcUser.getAuthcUserResponse());
        sessionMap.put(sign, sessionKeeper);
        return sign;
    }

    /**
     * 创建签名
     */
    private String createSign() {
        Random random = new Random(10);//指定种子数10
        StringBuilder sign = new StringBuilder("sign");
        sign.append(random.nextInt()).append(System.currentTimeMillis());
        return sign.toString();
    }

    /**
     * 注销
     *
     * @param sign
     */
    @Override
    public void layout(String sign) {
        try {
            String key = keyMap.get(sign);
            signMap.remove(key);
            sessionMap.remove(sign);
            keyMap.remove(sign);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 检查登陆状态
     *
     * @param sign
     * @return
     */
    @Override
    public boolean checkLogin(String sign) throws Exception {
        boolean isLogon = false;
        if (keyMap.containsKey(sign)) {
            String key = keyMap.get(sign);
            if (sessionMap.containsKey(sign) && signMap.containsKey(key)) {
                if(!checkTimeout(sign))
                 isLogon = true;
            }
        }
        return isLogon;
    }

    /**
     * 检查是否过期并清理
     *
     * @param sign
     * @return
     */
    private boolean checkTimeout(String sign) {
        boolean isTomeOut = false;
        Long oldTime = sessionMap.get(sign).getTimestamp();
        if ((System.currentTimeMillis() - oldTime) / (1000 * 60) > timeout) {
            isTomeOut = true;
            layout(sign);
        }
        return isTomeOut;
    }

    /**
     * 更新时间戳
     *
     * @param sign
     */
    private void updateTimestamp(String sign) {
        sessionMap.get(sign).setTimestamp(System.currentTimeMillis());
    }

    /**
     * 获取登陆用户数据
     *
     * @param sign
     * @return
     * @throws Exception
     */
    @Override
    public AuthcUserResponse getAuthcData(String sign) throws Exception {
        if (checkLogin(sign)) {
            updateTimestamp(sign);
            return sessionMap.get(sign).getAuthcUserResponse();
        } else throw new Exception("用户登陆已过期！");
    }

    /**
     * 修改登陆用户数据
     *
     * @param sign
     * @param json
     * @return
     * @throws Exception
     */
    @Override
    public void updateAuthcData(String sign, String json) throws Exception {
        if (checkLogin(sign)) {
            updateTimestamp(sign);
            sessionMap.get(sign).getAuthcUserResponse().setJson(json);
        } else throw new Exception("用户登陆已过期！");
    }

    /**
     * 清理过期数据
     */
    @Override
    public void clean() {
        keyMap.keySet().stream().forEach(sign->checkTimeout(sign));
    }
}

